﻿using System.Data;
using System;
using System.ComponentModel;
using System.Collections.Generic;
using System.Linq;
using System.Drawing;
using System.Web;
using System.Web.UI.WebControls;
using System.Text;
using System.Web.UI;
using System.Collections;

namespace Marbles.Core.Web.Controls
{
    [ToolboxData("<{0}:ExtendedGridView runat=server></{0}:ExtendedGridView>")]
    public class ExtendedGridView : GridView
    {

        [Category("Behaviour")]
        [Bindable(BindableSupport.No)]
        public bool ShowWhenEmpty
        {
            get
            {
                if (ViewState["ShowWhenEmpty"] == null) { ViewState["ShowWhenEmpty"] = true; }
                return (bool)ViewState["ShowWhenEmpty"];
            }
            set
            {
                ViewState["ShowWhenEmpty"] = value;
            }
        }

        [Category("Appearance")]
        public bool EnableMouseTrackingEffects
        {
            get
            {
                if (ViewState["EnableMouseTrackingEffects"] == null) { ViewState["EnableMouseTrackingEffects"] = true; }
                return (bool)ViewState["EnableMouseTrackingEffects"];
            }
            set
            {
                ViewState["EnableMouseTrackingEffects"] = value;
            }
        }

        [Category("Appearance")]
        public TableItemStyle GroupHeaderStyle { get { return this._GroupHeaderStyle; } }

        [Category("Appearance")]
        public TableItemStyle GroupFooterStyle { get { return this._GroupFooterStyle; } }

        [Category("Appearance")]
        [Bindable(BindableSupport.No)]
        public bool ShowGroupFooters
        {
            get
            {
                if (ViewState["ShowGroupFooters"] == null) { ViewState["ShowGroupFooters"] = true; }
                return (bool)ViewState["ShowGroupFooters"];
            }
            set
            {
                ViewState["ShowGroupFooters"] = value;
            }
        }

        [Category("Data")]
        public string GroupByNames
        {
            get
            {
                if (ViewState["GroupByNames"] == null) { ViewState["GroupByNames"] = string.Empty; }
                return ViewState["GroupByNames"] as string;
            }
            set { ViewState["GroupByNames"] = value; }
        }

        [Category("Data")]
        public string GroupByDisplayFormatString
        {
            get
            {
                if (ViewState["GroupByDisplayFormatString"] == null) { ViewState["GroupByDisplayFormatString"] = string.Empty; }
                return ViewState["GroupByDisplayFormatString"] as String;
            }
            set { ViewState["GroupByDisplayFormatString"] = value; }
        }

        [Category("Appearance")]
        public override GridViewRow FooterRow
        {
            get { return this.footerRow; }
        }

        [Category("Appearance")]
        public override GridViewRow HeaderRow
        {
            get { return this.headerRow; }
        }

        [Category("Data")]
        public int DataSourceRowCount { get { return this._dataSourceRowCount; } }

        internal string[] GroupByDataKeys { get { return this.GroupByNames.Split(','); } }

        private TableItemStyle _GroupHeaderStyle = new TableItemStyle();
        private TableItemStyle _GroupFooterStyle = new TableItemStyle();
        private IList InternalDataSource = null;
        private int _dataSourceRowCount = 0;
        private GridViewRow headerRow;
        private GridViewRow footerRow;
        private Dictionary<string, object> GroupByKeys = null;
        private bool CreateSub = false;
        private int subtotal = 0;

        public delegate void SubHeadingCreatedEventHandler(object sender, GridViewRowEventArgs e);
        public event SubHeadingCreatedEventHandler SubHeadingCreated;
        public delegate void SubFooterCreatedEventHandler(object sender, GridViewSubFooterRowEventArgs e);
        public event SubFooterCreatedEventHandler SubFooterCreated;

        public ExtendedGridView()
            : base()
        {
            this.UseAccessibleHeader = true;
        }

        protected override void OnDataBinding(EventArgs e)
        {
            InternalDataSource = ((IListSource)DataSource).GetList();
            _dataSourceRowCount = InternalDataSource.Count;
            base.OnDataBinding(e);
        }

        protected void OnSubFooterCreated(GridViewSubFooterRowEventArgs e)
        {
            if (SubFooterCreated != null) { SubFooterCreated(this, e); }
        }

        protected void OnSubHeadingCreated(GridViewRowEventArgs e)
        {
            if (SubHeadingCreated != null) { SubHeadingCreated(this, e); }
        }

        protected override void OnRowCreated(GridViewRowEventArgs e)
        {
            if (e.Row.RowType != DataControlRowType.DataRow) { return; }

            if (this.GroupByNames.Length > 0)
            {
                if ((CreateSub) || (e.Row.RowIndex == 0))
                {
                    if (e.Row.RowIndex == 0) { GroupByKeys = CreateDataKey(e.Row); }
                    if ((e.Row.RowIndex > 0) && (ShowGroupFooters))
                    {
                        ((Table)this.Controls[0]).Rows.Add(CreateSubFooterRow(GroupByKeys, e.Row));
                    }

                    ((Table)this.Controls[0]).Rows.Add(CreateSubHeadingRow(GroupByKeys, e.Row));
                    CreateSub = false;
                }
            }
            base.OnRowCreated(e);
        }

        private GridViewRow CreateSubFooterRow(Dictionary<string, object> CurrentKey, GridViewRow Row)
        {
            GridViewRow subrow = new GridViewRow(Row.RowIndex + 1, 0, DataControlRowType.DataRow, DataControlRowState.Normal);
            TableCell tc = new TableCell();
            ArrayList values = new ArrayList();
            tc.ColumnSpan = Row.Cells.Count;

            foreach (string s in CurrentKey.Keys)
            {
                values.Add(CurrentKey[s]);
            }


            subrow.Cells.Add(tc);

            if (this._GroupFooterStyle != null) { subrow.ApplyStyle(this._GroupFooterStyle); }

            OnSubFooterCreated(new GridViewSubFooterRowEventArgs(subtotal, subrow));
            subtotal = 0;
            return subrow;
        }

        private GridViewRow CreateSubHeadingRow(Dictionary<string, object> CurrentKey, GridViewRow Row)
        {
            GridViewRow subrow = new GridViewRow(Row.RowIndex + 1, 0, DataControlRowType.DataRow, DataControlRowState.Normal);
            TableCell tc = new TableCell();
            ArrayList values = new ArrayList();
            tc.ColumnSpan = Row.Cells.Count;

            foreach (string s in CurrentKey.Keys)
            {
                values.Add(CurrentKey[s]);
            }

            if (values.Count > 0) { tc.Text = string.Format(this.GroupByDisplayFormatString, values.ToArray()); }
            subrow.Cells.Add(tc);

            if (this._GroupHeaderStyle != null) { subrow.ApplyStyle(this._GroupHeaderStyle); }

            OnSubHeadingCreated(new GridViewRowEventArgs(subrow));
            return subrow;
        }

        protected override void OnRowDataBound(GridViewRowEventArgs e)
        {
            base.OnRowDataBound(e);

            if (e.Row.RowType != DataControlRowType.DataRow) { return; }

            CreateSub = false;
            subtotal += 1;

            if (this.GroupByNames.Length > 0)
            {
                CreateSub = false;

                if ((e.Row.RowIndex == -1) || (e.Row.RowIndex + 1 < this.InternalDataSource.Count))
                {
                    Dictionary<string, object> CurrentKey = CreateDataKey(e.Row);
                    Dictionary<string, object> NextKey = CreateDataKey(this.InternalDataSource[e.Row.RowIndex + 1] as DataRowView);

                    foreach (string s in CurrentKey.Keys)
                    {
                        if (Comparer.Default.Compare(CurrentKey[s], NextKey[s]) != 0)
                        {
                            GroupByKeys = NextKey;
                            CreateSub = true; break;
                        }
                    }
                }
            }

            if (EnableMouseTrackingEffects)
            {

                e.Row.Attributes.Add("onmouseover", "this.style.background = '#cecfce';");
                e.Row.Attributes.Add("onmouseout", "this.style.background = '" + System.Drawing.ColorTranslator.ToHtml(e.Row.BackColor) + "';");
            }

        }


        private Dictionary<string, object> CreateDataKey(DataRowView DataItem)
        {
            Dictionary<string, object> items = new Dictionary<string, object>();
            System.Collections.Specialized.OrderedDictionary keyTable = new System.Collections.Specialized.OrderedDictionary();

            foreach (string field in this.GroupByDataKeys)
            {
                if (DataItem != null)
                {
                    items.Add(field, DataItem[field]);
                }
            }

            return items;
        }

        private Dictionary<string, object> CreateDataKey(GridViewRow Row)
        {
            return CreateDataKey(Row.DataItem as DataRowView);
        }

        protected override int CreateChildControls(System.Collections.IEnumerable dataSource, bool dataBinding)
        {
            int numRows = base.CreateChildControls(dataSource, dataBinding);

            if (numRows == 0 && ShowWhenEmpty)
            {
                Table table = new Table();
                table.ID = this.ID;

                DataControlField[] fields = new DataControlField[this.Columns.Count];
                this.Columns.CopyTo(fields, 0);

                if (this.ShowHeader)
                {
                    this.headerRow = base.CreateRow(-1, -1, DataControlRowType.Header, DataControlRowState.Normal);

                    this.InitializeRow(headerRow, fields);
                    table.Rows.Add(headerRow);
                }

                GridViewRow emptyRow = new GridViewRow(-1, -1, DataControlRowType.EmptyDataRow, DataControlRowState.Normal);

                TableCell cell = new TableCell();
                cell.ColumnSpan = this.Columns.Count;
                cell.Width = Unit.Percentage(100);
                if (!String.IsNullOrEmpty(EmptyDataText)) { cell.Controls.Add(new LiteralControl(EmptyDataText)); }

                if (this.EmptyDataTemplate != null) { EmptyDataTemplate.InstantiateIn(cell); }

                emptyRow.Cells.Add(cell);
                table.Rows.Add(emptyRow);

                if (this.ShowFooter)
                {
                    this.footerRow = base.CreateRow(-1, -1, DataControlRowType.Footer, DataControlRowState.Normal);
                    this.InitializeRow(footerRow, fields);
                    table.Rows.Add(footerRow);
                }

                this.Controls.Clear();
                this.Controls.Add(table);
            }
            else
            {
                if (this.ShowGroupFooters)
                {
                    ((Table)this.Controls[0]).Rows.Add(CreateSubFooterRow(GroupByKeys, this.Rows[this.Rows.Count - 1]));
                }
                this.footerRow = base.FooterRow;
                this.headerRow = base.HeaderRow;
            }

            return numRows;
        }
    }
}
